
package boundary;

import entity.State;
import java.util.Random;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextArea;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;

/**
 * @version 1.0
 * @date 13/04/2012
 * @author john
 */
public class ProgressPane extends GridPane{
    
    private long totalLinesNumber;
    private long fileID;
    
    private final double minControlsWidth=400;
    private final double minTextAHeight=200;
    private final DoubleProperty controlsWidthProperty;
    private final DoubleProperty stateTAHeightProperty;
    
    private final Label fileIDL;
    private final Label fileIDL2;
    private final Label percentageL;
    private final ProgressBar progressBar;
    private final TextArea stateTA;
    
    private final Application application;

    public ProgressPane(final Scene mainScene, Application application, long fileID, long totalLinesNumber) {
        this.application=application;
        this.fileID=fileID;
        this.totalLinesNumber=totalLinesNumber;
        setId("progress-bar");
        setPadding(new Insets(25, 40, 20, 40));
        setVgap(10);
        controlsWidthProperty=new SimpleDoubleProperty();
        controlsWidthProperty.bind(mainScene.widthProperty().subtract(this.getPadding().getLeft()).subtract(this.getPadding().getRight()));
        stateTAHeightProperty=new SimpleDoubleProperty();
        stateTAHeightProperty.bind(mainScene.heightProperty().subtract(this.getPadding().getTop()).subtract(this.getPadding().getBottom()).subtract(110));
        HBox fileIDHBox=new HBox(7);
        fileIDL=new Label("ID del archivo:");
        fileIDL2=new Label(String.valueOf(String.valueOf(fileID)));
        fileIDHBox.getChildren().setAll(fileIDL,fileIDL2);
        percentageL=new Label("Líneas Procesadas / Líneas Totales");
        GridPane.setHalignment(percentageL, HPos.CENTER);
        progressBar=new ProgressBar(0);
        progressBar.setMinWidth(minControlsWidth);
        progressBar.prefWidthProperty().bind(controlsWidthProperty);
        stateTA=new TextArea();
        stateTA.setMinHeight(minTextAHeight);
        stateTA.setEditable(false);
        stateTA.prefWidthProperty().bind(controlsWidthProperty);
        stateTA.prefHeightProperty().bind(stateTAHeightProperty);
        add(fileIDHBox, 0, 0);
        add(percentageL, 0, 1);
        add(progressBar, 0, 2);
        add(stateTA, 0, 3);
    }
    
    /**
     * Inicializa el thread de consulta y relaciona su progreso con los
     * elementos graficos que informan al usuario del avance.
     * @param fileAnalysisTask 
     */
    protected Task createTask(){
        Task fileAnalysisTask=checkProgress();
        progressBar.progressProperty().unbind();
        progressBar.setProgress(0);
        progressBar.progressProperty().bind(fileAnalysisTask.progressProperty());
        fileAnalysisTask.progressProperty().addListener(
            new ChangeListener<Number>() {
                @Override
                public void changed(ObservableValue<? extends Number> arg0, Number oldLinesNumber, Number newLinesNumber) {
                    percentageL.setText(((int)(newLinesNumber.doubleValue()*totalLinesNumber))+" / "+totalLinesNumber);
                    if(newLinesNumber.intValue()==1)
                        ((MainWindow)application).endFileAnalysis();
                }
            }
        );
        fileAnalysisTask.messageProperty().addListener(
            new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> arg0, String oldMessage, String newMessage) {
                    stateTA.appendText(newMessage+"\n");
                }
            }
        );
        return fileAnalysisTask;
    }
    
    /**
     * Inicializa el thread de consulta a la base de datos para conocer el estado
     * de la revisión del archivo
     * @return Task: una tarea que consulta constantemente el estado de analisis 
     * de un archivo
     */
    private Task checkProgress(){
        return new Task(){
            @Override
            protected Object call() throws Exception {
                entity.State state;
                int i=0;
                while(true){
                    state=checkLinesStateFromDB(++i);
                    if(state!=null && state.isInformative()){
                        if(state.isCompleted())
                            break;
                        updateMessage(state.getMessage());
                        updateProgress(state.getLine(), totalLinesNumber);
                    }
                }
                updateProgress(totalLinesNumber, totalLinesNumber);
                updateMessage("Archivo completado.");
                return true;
            }
        };
    }
    
    /**
     * Consulta el estado del archivo en la base de datos por medio de la 
     * llamada a un metodo de control. En algun momento el control debe retornar
     * un state con atributo completed=true para terminar la tarea.
     * @return objeto State con la información del avance del análisis del archivo
     */
    private State checkLinesStateFromDB(int i) throws InterruptedException{
        // esto es una prueba de funcionamiento
        if(i==this.totalLinesNumber)
            return new State(true);
        long systemMillis=System.currentTimeMillis();
        Random random=new Random(systemMillis);
        Thread.sleep(random.nextInt((int)1000));
        return new State("probando, no es un resultado real: "+i, i, random.nextBoolean());
    }
    
}